/***********************************************************************************************//**
*\n  @file       device_uart.cpp
*\n  @brief      RS232/RS485设备类
*\n  @details
*\n -----------------------------------------------------------------------------------
*\n  文件说明：
*\n       1. RS232/RS485设备类
*\n
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.01   罗先能        2021.5.12          创建
*\n
***************************************************************************************************/

/**************************************************************************************************
* 头文件
***************************************************************************************************/
#include <iostream>
#include "bus_spi.hpp"
#include "device_gpio.hpp"
#include "device_uart.hpp"

#undef  DEBUG_LEVEL
#define DEBUG_LEVEL  5   // 定义debug级别 (0 ~ 5)
#include "vdebug.h"

using namespace std;

/**************************************************************************************************
* 宏定义、结构定义
***************************************************************************************************/
#ifdef  __cplusplus //-- C only -----------------------------------------------------------
extern "C" {
#endif


#ifdef  __cplusplus //--C end -------------------------------------------------------------
}
#endif

/**************************************************************************************************
* 全局变量声明、定义
***************************************************************************************************/


/**************************************************************************************************
* 私有变量声明、定义
***************************************************************************************************/
// 静态成员变量初始化:
TRs232FromSpi *TRs232FromSpi::tSelf[2] = { NULL, NULL };
TBus*          TRs232FromSpi::pIfSpi   = NULL;
TDevice*       TRs232FromSpi::pIfGpio  = NULL;
pthread_t      TRs232FromSpi::iTid     = -1;
int            TRs232FromSpi::gpioFd   = -1;
int            TRs232FromSpi::iReference = 0;

/**************************************************************************************************
* 私有函数声明、定义
***************************************************************************************************/

// 线程:gpio中断处理线程(静态函数)
void* TRs232FromSpi::GpioInterruptTask(void *arg)
{
    while (1)
    {
    	// 等待gpio中断
        int ret = pIfGpio->Read(null, NULL, null);
        if (ret <= 0)
        { // error
            continue;
        }

        /*
        // 读取spi2uart的中断状态值IIR(并清除中断标志);
        //   通道0:Bit[0~15], 通道1:Bit[16~31];
		//   IIR[5:0],  Priority level, Interrupt type,       Interrupt source
		//   000001,    none,           none,                 none;
		//   000110,    1,              receiver line status, Overrun Error (OE), Framing Error (FE), Parity Error(PE),
		//		                                           or Break Interrupt (BI) errors occur in characters in the RX FIFO
		//   001100,    2,              RX time-out,          stale data in RX FIFO;
		//   000100,    2,              RHR interrupt,        receive data ready (FIFO disable) or
		//		                                           RX FIFO above trigger level (FIFO enable)
		//   000010,    3,              THR interrupt,        transmit FIFO empty (FIFO disable) or
		//		                                           TX FIFO passes above trigger level (FIFO enable)
		//   000000,    4,              modem status,         change of state of modem input pins
		//	 001110,    5,              I/O pins,             input pins change of state
		//	 010000,    6,              Xoff interrupt,       receive Xoff character(s)/special character
		//   100000,    7,              CTS/RTS,              RTS pin or CTS pin change state from active (LOW) to inactive (HIGH)
		*/
        u32 status;
        ret = TRs232FromSpi::pIfSpi->Ioctl(GET_STATUS, &status);
        if (ret < 0)
        {
            // debug_error("Ioctl() < 0\n");
            continue;
        }
		if ((status & 0x00040004) == 0)
		{
			// debug_error("status == 0x%08x \n", status);
			continue;
		}
		//debug_printf("status == 0x%08x \n", status);

        // 接收通道0数据;
        if (status & 0x0004)
        {
        	int channel = 0;
            // debug_printf("recv channel[%d]\n", channel);
            if(tSelf[channel] != NULL)
            {
            	TRs232FromSpi *self = tSelf[channel];
            	self->IrqRead(channel);
            }
        }

		// 接收通道1数据;
        if ((status >> 16) & 0x0004)
        {
        	int channel = 1;
            // debug_printf("recv channel[%d]\n", channel);
            if(tSelf[channel] != NULL)
            {
            	TRs232FromSpi *self = tSelf[channel];
            	self->IrqRead(channel);
            }
        }
    }

    pthread_exit(NULL);
}


/**************************************************************************************************
* 全局函数声明、定义
***************************************************************************************************/
TRs232FromSpi::TRs232FromSpi(const char *name, TDevice *pGpio, TBus *pSpi, u32 index)
{
    if(index >= 2)
    {
        debug_error("%s->index == %d\n", name, index);
        return;
    }

    // 1. 保存名称
	memset(this->mName, 0, sizeof(this->mName));
	int iSize = sizeof(this->mName) - 1;
	iSize = iSize < strlen(name)  ? iSize : strlen(name);
	memcpy(this->mName, name, iSize);

	sem_init(&this->sem, 0, 0);

    this->pBus = pSpi;           // spi总线

    //{{{ 静态参数(只需要1次)
	TRs232FromSpi::tSelf[index] =  this;
    if(NULL == TRs232FromSpi::pIfSpi)
        TRs232FromSpi::pIfSpi = pSpi;      // spi实例
    if(NULL == TRs232FromSpi::pIfGpio)
    	TRs232FromSpi::pIfGpio = pGpio;    // gpio实例
    //}}}
}

TRs232FromSpi::~TRs232FromSpi()
{
}

// virtual
int TRs232FromSpi::Open(void *pHandle)
{
    if((NULL == pHandle) || (NULL == pBus) || (NULL == pIfGpio))
    {
        if(NULL == pHandle)
            debug_error("NULL == pHandle \n");
        else if(NULL == pBus)
            debug_error("NULL == pHandle \n");
        else if(NULL == pIfGpio)
            debug_error("NULL == pGpioDevice \n");

        return -1;
    }

    int ret;
    TRs232Handle *tHandle1 = (TRs232Handle *)pHandle;
    // 设置波特率
    ret = pBus->Ioctl(SET_BPS, (void*)tHandle1->iBandrate);
    if (ret < 0)
    {
        debug_error("Ioctl(SET_BPS) < 0\n");
        return -1;
    }
    // 设置停止位
    ret = pBus->Ioctl(SET_STOP_BIT, (void*)tHandle1->iStopBit);
    if (ret < 0)
    {
        debug_error("Ioctl(SET_STOP_BIT) < 0\n");
        return -1;
    }
    // 设置奇偶校验位
	ret = pBus->Ioctl(SET_PARITY, (void*)tHandle1->iParity);
	if (ret < 0)
	{
		// debug_error("Ioctl(SET_PARITY) < 0\n");
		// return -1;
	}

    this->iReference++;
    // 开启gpio
    if(TRs232FromSpi::gpioFd == -1)
    {
        TRs232FromSpi::gpioFd = pIfGpio->Open(NULL);
        if (TRs232FromSpi::gpioFd < 0)
        {
            debug_error("pIfGpio->Open() < 0\n");
            return -1;
        }
    }

	// 创建gpio口的监控线程
	// 设置线程优先级
	if(-1 == TRs232FromSpi::iTid)  // 只创建1次;
	{
		static pthread_attr_t attr;
		pthread_attr_init(&attr);
		pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
		pthread_attr_setschedpolicy(&attr, SCHED_RR);
		static struct sched_param param;
		param.sched_priority = 60;
		pthread_attr_setschedparam(&attr, &param);
		// 中断处理线程
		int ret = pthread_create(&TRs232FromSpi::iTid, &attr,
                                  TRs232FromSpi::GpioInterruptTask, NULL);
		if(0 != ret)
		{
			TRs232FromSpi::iTid = -1;
			printf("pthread_create() %s\n", strerror(errno));
			return -1;
		}

	}
    return  0;
}

// virtual
int TRs232FromSpi::Close(void *pHandle)
{
    // TRs232Handle *handle = (TRs232Handle *)pHandle;

    // 处理静态函数等
    this->iReference--;
    if ( this->iReference <= 0)
    {
        pthread_cancel(TRs232FromSpi::iTid);
        TRs232FromSpi::iTid = -1;
        // 关闭gpio
        pIfGpio->Close(NULL);
    }
    return 0;
}

// 中断中调用,读取spi数据;
void TRs232FromSpi::IrqRead(int channel)
{
    mRxSize = pBus->Read(0, mRxIrqBuffer, sizeof(mRxIrqBuffer));  // spi接口
    if (mRxSize > 0)
    {
		sem_post(&(this->sem));
	}
}

// virtual
int TRs232FromSpi::Read(long address, void *pBuf, long iSizeToRead)
{
    // 等待gpio中断, 并通过spi读取数据
	sem_wait(&(this->sem));

    long ret = iSizeToRead < mRxSize ? iSizeToRead : mRxSize;
    memcpy(pBuf, this->mRxIrqBuffer, ret);
    return ret;
}

// virtual
int TRs232FromSpi::Write(long address, void *pBuf, long iSizeToWrite)
{
    int ret;
    ret = pBus->Write(0, pBuf, iSizeToWrite);
    return ret;
}


